package ch.eureka.consumer.ribbon.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.ObservableExecutionMode;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import com.netflix.hystrix.exception.HystrixBadRequestException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import rx.Subscriber;

import java.util.Observable;
import java.util.concurrent.Future;

/**
 *  Hystrix断路器的使用 注解形式
 */
@Service
public class ProviderWithHystrix {

    @Autowired
    RestTemplate template;

    /**
     * 同步
     * ignoreExceptions : 忽略指定异常
     * @return
     */
//    @CacheResult(cacheKeyMethod = "getCacheKey") // 缓存结果值
    @HystrixCommand(
            fallbackMethod = "serviceError", // 降级指定方法
            ignoreExceptions = HystrixBadRequestException.class, // 忽略某个异常，不进入fallbackMethod
            commandKey = "hello", // 命令名称
            groupKey = "group", // 命令分组
            threadPoolKey = "helloThread" // 指定线程池
    )
    public String hello(Long id){
        /**
         *  getForEntity("地址?name={1}",返回数据的格式,"数据")
         */
        return template.getForEntity("http://eureka-provider/hello",String.class).getBody();
    }

    /**
     * 缓存key方法
     * 也可以用@cacheKey 优先级没有cacheKeyMethod高
     *          eg： public String hello(@CacheKey("id")Long id){}
     * @param id
     * @return
     */
    public String getCacheKey(Long id){
        // 可以对缓存的key进行处理
        return "11";
    }

    /**
     * 进行更新的时候，要清除之前的缓存
     * @param id
     */
    @CacheRemove(commandKey = "hello") // commandKey是必须指定,指定方法
    @HystrixCommand
    public void updateInfo(@CacheKey("id")Long id){

    }

    /**
     * 异步
     * @return
     */
    @HystrixCommand
    public Future<String> getResultByAsync(){
        return new AsyncResult<String>() {
            @Override
            public String invoke() {
                return template.getForEntity("http://eureka-provider/hello",String.class).getBody();
            }
        };
    }

    /**
     *  observable形式
     *      执行方式的话有两种 : 1.每次订阅Hot(ObservableExecutionMode.EAGER)   2.全部订阅Cold(ObservableExecutionMode.LAZY)
     * @return
     */
    @HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER)
    public rx.Observable<String> getResultByObservable(){
        return rx.Observable.create(new rx.Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                try {
                    if(subscriber.isUnsubscribed()){
                        // 没有订阅
                        // 执行操作
                        String s = "执行操作结果";
                        subscriber.onNext(s);
                        subscriber.onCompleted();
                    }
                }catch (Exception e) {
                    subscriber.onError(e);
                }
            }
        });
    }

    /**
     * 降级时调用的方法
     * @return
     */
    public String serviceError(Long id){
        return "Found service error";
    }
}
